<?php
/**
 * 微信基础类
 * #1常用参数初始化，例如appID,appSecret
 * #2token获取
 * #3发送http请求
 * @author xiegaolei
 *
 */

class Wechat {
    
    /**
     * access_token保存路径
     */
    private $access_ticket_path  = './weixin/data/access_token.json';
    
    /**
     * 微信开发者申请的appID
     * @var string
     */
    protected $appId = '';

    /**
     * 微信开发者申请的appSecret
     * @var string
     */
    protected $appSecret = '';
 

    /**
     * 微信api根路径
     * @var string
     */
    protected $apiURL    = 'https://api.weixin.qq.com/cgi-bin';
    

    /**
     * 构造方法，调用微信高级接口时实例化SDK
     * @param string $appid  微信appid
     * @param string $secret 微信appsecret
     */
    public function __construct($appid, $secret){
        if($appid && $secret){
            $this->appId     = $appid;
            $this->appSecret = $secret;
 
        } else {
            throw new Exception('参数错误！');
        }
    }
    
    /**
     * [getAccessToken 获取普通access_token]
     * @return [type] [description]
     */
    protected function getAccessToken() {
        // access_token 应该全局存储与更新
        $access_token_file = $this->access_ticket_path;
        $data = json_decode(file_get_contents($access_token_file));
        if ($data->expire_time < time()) {
            // 如果是企业号用以下URL获取access_token
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
            $params = array(
                'appid'         => $this->appId,
                'secret'        => $this->appSecret,
                'grant_type'    => 'client_credential',
            );
            
            $url = $this->apiURL.'/token';
            $res = json_decode($this->http($url,$params));
            $access_token = $res->access_token;
            if ($access_token) {
                $data->expire_time = time() + 7000;
                $data->access_token = $access_token;
                $fp = fopen($access_token_file, "w");
                fwrite($fp, json_encode($data));
                fclose($fp);
            }else{
				throw new Exception('错误code:'.$res->errcode.',错误：'.$res->errmsg);
			}
        } else {
            $access_token = $data->access_token;
        }
        
        return $access_token;
    }
    
    /**
     * 获取微信服务器IP地址列表
     * [getCallbackIp ]
     * @param unknown $token
     */
    protected function getCallbackIp($token){
        if (empty($token)){
            throw new Exception('token不能为空！');
        }
        
        $param = array(
            'access_token'  => $token
        );
     
        $url = "{$this->apiURL}/getcallbackip";
    
        $res = $this->http($url, $param);
        $res = json_decode($res, true);
    
        if(is_array($res)){
            if(isset($res['errcode'])){
                throw new Exception($res['errmsg']);
            } else {                 
                return $res;
            }
        } else {
            throw new Exception('获取微信access_token失败！');
        }
        
    }
 
    /**
     * 发送HTTP请求方法，目前只支持CURL发送请求
     * @param  string $url    请求URL
     * @param  array  $param  GET参数数组
     * @param  array  $data   POST的数据，GET请求时该参数无效
     * @param  string $method 请求方法GET/POST
     * @return array          响应数据
     */
    protected  function http($url, $param, $data = '', $method = 'GET'){
        $opts = array(
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
        );

        /* 根据请求类型设置特定参数 */
        $opts[CURLOPT_URL] = $url . '?' . http_build_query($param);

        if(strtoupper($method) == 'POST'){
            $opts[CURLOPT_POST] = 1;
            $opts[CURLOPT_POSTFIELDS] = $data;
            
            if(is_string($data)){ //发送JSON数据
                $opts[CURLOPT_HTTPHEADER] = array(
                    'Content-Type: application/json; charset=utf-8',  
                    'Content-Length: ' . strlen($data),
                );
            }
        }

        /* 初始化并执行curl请求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $result  = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        //发生错误，抛出异常
        if($error) throw new Exception('请求发生错误：' . $error);

        return  $result;
    }

    /**
     * 调用微信api获取响应数据
     * @param  string $name   API名称
     * @param  string $data   POST请求数据
     * @param  string $method 请求方式
     * @param  string $param  GET请求参数
     * @return array          api返回结果
     */
    protected function api($name, $data = '', $method = 'POST', $param = ''){
        $token = $this->getAccessToken();
    
        $params = array('access_token' => $token);
    
        if(!empty($param) && is_array($param)){
            $params = array_merge($params, $param);
        }
    
        $url  = "{$this->apiURL}/{$name}";
        if(!empty($data)){
            //保护中文，微信api不支持中文转义的json结构
            array_walk_recursive($data, function(&$value){
                $value = urlencode($value);
            });
            $data = urldecode(json_encode($data));
        }
        
        $data = $this->http($url, $params, $data, $method);
    
        return json_decode($data, true);
    } 

}
